﻿Imports System.Drawing
Imports System.Windows.Forms
Imports ajayumi.develop.VBasic.Core.Win.WinAPI

Namespace Forms.ImageForm

    ''' <summary>
    ''' 图片窗体的基类，继承该类的窗体可以使用图片作为窗体的主体
    ''' Author : ajayumi
    ''' Date   : 2010-10-01
    ''' </summary>
    ''' <remarks></remarks>
    Public MustInherit Class ImageFormBase
        Inherits FormBase

#Region "variables"
        Private m_haveHandle As Boolean = False

        Private Const AC_SRC_OVER As Byte = 0
        Private Const AC_SRC_ALPHA As Byte = 1
        Private Const ULW_ALPHA As Integer = 2
#End Region

#Region "properties"

        Protected m_FormImage As Image = Nothing
        ''' <summary>
        ''' 窗体的图片
        ''' </summary>
        Public ReadOnly Property FormImage() As Image
            Get
                Return m_FormImage
            End Get
        End Property

        Private m_Tip As String = String.Empty
        ''' <summary>
        ''' 提示
        ''' </summary>
        Public Property Tip() As String
            Get
                Return m_Tip
            End Get
            Set(ByVal value As String)
                m_Tip = value
            End Set
        End Property


        Private m_ShowTip As Boolean = False
        ''' <summary>
        ''' 是否显示提示
        ''' </summary>
        Public Property ShowTip() As Boolean
            Get
                Return m_ShowTip
            End Get
            Set(ByVal value As Boolean)
                m_ShowTip = value
            End Set
        End Property



        Private m_TipHorizontalAlign As TipHorizontalAlign = TipHorizontalAlign.Center
        ''' <summary>
        ''' 提示的水平位置
        ''' </summary>
        Public Property [TipHorizontalAlign]() As TipHorizontalAlign
            Get
                Return m_TipHorizontalAlign
            End Get
            Set(ByVal value As TipHorizontalAlign)
                m_TipHorizontalAlign = value
            End Set
        End Property


        Private m_TipVerticalAlign As TipVerticalAlign = TipVerticalAlign.Center
        ''' <summary>
        ''' 提示的垂直位置
        ''' </summary>
        Public Property [TipVerticalAlign]() As TipVerticalAlign
            Get
                Return m_TipVerticalAlign
            End Get
            Set(ByVal value As TipVerticalAlign)
                m_TipVerticalAlign = value
            End Set
        End Property



#End Region

        Public Sub New()
            MyBase.New()

            Me.DoubleBuffered = True
            Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
            Me.Name = "ImageFormBase"
            Me.ShowIcon = False
            Me.ShowInTaskbar = False

            Me.TopMost = True
        End Sub

#Region "events"

        ''' <summary>
        ''' 默认情况下，是双击鼠标退出，可以重写该事件
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Protected Overridable Sub Form_MouseDoubleClick(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseDoubleClick
            If e.Button = Windows.Forms.MouseButtons.Left Then
                Me.Close()
            End If
        End Sub

        Protected Overridable Sub Form_MouseEnter(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.MouseEnter
            If Me.ShowTip = False OrElse String.IsNullOrEmpty(Me.Tip) Then
                Exit Sub
            End If

            Dim _TempStr As String = Me.Tip
            Dim _Font As Font = Nothing
            Dim _FontPoint As Point = Point.Empty
            Dim _FontSize As Size = Nothing
            Dim _FontBrush As New SolidBrush(Color.FromArgb(150, 0, 0, 0))

            '主体图像的矩形区域
            Dim _ImageRectangle As Rectangle = Rectangle.Empty
            Dim _NewImageWidth As Integer = 0, _NewImageHeight As Integer = 0
            '窗体的左边距，上边距
            Dim _FormLeft As Integer = Me.Left, _FormTop As Integer = Me.Top
            Dim _BorderPen As New Pen(Color.FromArgb(200, 103, 133, 170), 2)
            '偏移值
            Dim _OffsetX As Integer = 0, _OffsetY As Integer = 0

            Using _ImageClone As Image = DirectCast(Me.FormImage.Clone(), Image)
                With _ImageRectangle
                    .X = 0 : .Y = 0 : .Width = _ImageClone.Width : .Height = _ImageClone.Height
                End With

                _Font = New Font("Cambria", 14.0!, FontStyle.Bold, GraphicsUnit.Pixel)
                _FontSize = TextRenderer.MeasureText(_TempStr, _Font)

                _NewImageWidth = _ImageRectangle.Width
                _NewImageHeight = _ImageRectangle.Height

                'Tip的坐标
                Select Case Me.TipHorizontalAlign
                    Case TipHorizontalAlign.InnerLeft
                        _FontPoint.X = 0
                        If _FontSize.Width > _ImageRectangle.Width Then
                            _NewImageWidth = _FontSize.Width
                        End If
                        Exit Select
                    Case TipHorizontalAlign.InnerRight
                        _FontPoint.X = _ImageRectangle.Width - _FontSize.Width
                        If _FontSize.Width > _ImageRectangle.Width Then
                            _OffsetX = -(_FontSize.Width - _ImageRectangle.Width)
                            _ImageRectangle.X -= _OffsetX
                            _NewImageWidth = _FontSize.Width
                            _FontPoint.X = 0
                        End If
                        Exit Select
                    Case TipHorizontalAlign.OuterLeft
                        _FontPoint.X = 0
                        _OffsetX = -_FontSize.Width
                        _ImageRectangle.X -= _OffsetX
                        _NewImageWidth += _FontSize.Width
                        Exit Select
                    Case TipHorizontalAlign.OuterRight
                        _FontPoint.X = _ImageRectangle.Width
                        _NewImageWidth += _FontSize.Width
                        Exit Select
                    Case Else
                        _FontPoint.X = CInt((_ImageRectangle.Width - _FontSize.Width) / 2)
                        If _FontSize.Width > _ImageRectangle.Width Then
                            _OffsetX = -CInt((_FontSize.Width - _ImageRectangle.Width) / 2)
                            _ImageRectangle.X -= _OffsetX
                            _NewImageWidth = CInt(_FontSize.Width)
                            _FontPoint.X = 0
                        End If
                        Exit Select
                End Select
                Select Case Me.TipVerticalAlign
                    Case TipVerticalAlign.InnerTop
                        _FontPoint.Y = 0
                        Exit Select
                    Case TipVerticalAlign.InnerBottom
                        _FontPoint.Y = _ImageRectangle.Height - _FontSize.Height
                        Exit Select
                    Case TipVerticalAlign.OuterTop
                        _FontPoint.Y = 0
                        _OffsetY = -_FontSize.Height
                        _ImageRectangle.Y -= _OffsetY
                        _NewImageHeight += _FontSize.Height
                        Exit Select
                    Case TipVerticalAlign.OuterBottom
                        _FontPoint.Y = _ImageRectangle.Height
                        _NewImageHeight += _FontSize.Height
                        Exit Select
                    Case Else
                        _FontPoint.Y = CInt((_ImageRectangle.Height - _FontSize.Height) / 2)
                        Exit Select
                End Select

                Try

                    Using _Bitmap As New Bitmap(_NewImageWidth, _NewImageHeight)
                        Using _Graphics As Graphics = Graphics.FromImage(_Bitmap)
                            With _Graphics
                                '绘制主体背景
                                .FillRectangle(New SolidBrush(Color.FromArgb(100, 103, 133, 170)), _
                                               _ImageRectangle)
                                '绘制主体图像
                                .DrawImage(_ImageClone, _ImageRectangle)
                                '绘制边框
                                '.DrawRectangle(_BorderPen, _
                                '              New Rectangle(CInt(_BorderPen.Width / 2), _
                                '                            CInt(_BorderPen.Width / 2), _
                                '                            _NewImageWidth - CInt(_BorderPen.Width), _
                                '                            _NewImageHeight - CInt(_BorderPen.Width)))
                                .DrawRectangle(_BorderPen, _
                                               New Rectangle(_ImageRectangle.Left + CInt(_BorderPen.Width / 2), _
                                                             _ImageRectangle.Top + CInt(_BorderPen.Width / 2), _
                                                             _ImageRectangle.Width - CInt(_BorderPen.Width), _
                                                             _ImageRectangle.Height - CInt(_BorderPen.Width)))
                                '绘制文字背景
                                .FillRectangle(_FontBrush, _
                                               _FontPoint.X, _FontPoint.Y, _
                                               _FontSize.Width, _FontSize.Height)
                                '绘制文字
                                .DrawString(_TempStr, _Font, Brushes.White, _FontPoint)
                            End With

                            Me.UpdateVisual(_Bitmap, _FormLeft + _OffsetX, _FormTop + _OffsetY)
                        End Using
                    End Using

                Catch ex As Exception
                Finally
                    _Font.Dispose() : _Font = Nothing
                    _FontPoint = Nothing
                    _FontBrush.Dispose() : _FontBrush = Nothing
                End Try
            End Using
        End Sub

        Protected Overridable Sub Form_MouseLeave(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.MouseLeave
            If Me.ShowTip = False OrElse String.IsNullOrEmpty(Me.Tip) Then
                Exit Sub
            End If
            Me.UpdateVisual(Me.FormImage)
        End Sub

#End Region

#Region "methods"

        '[private]----------------------------------------------------------------------------------------
        ''' <summary>
        ''' 显示器的中心
        ''' </summary>
        Private Function ScreenCenterPoint() As Point
            Return New Drawing.Point(CInt(My.Computer.Screen.WorkingArea.Width / 2), _
                                     CInt(My.Computer.Screen.WorkingArea.Height / 2))
        End Function

        Private Sub initializeStyles()
            Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
            Me.SetStyle(ControlStyles.UserPaint, True)
            Me.UpdateStyles()
        End Sub



        '[protected]----------------------------------------------------------------------------------------
        ''' <summary>
        ''' 初始化窗体图片
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Protected MustOverride Function InitFormImage() As Image
        ''' <summary>
        ''' 默认的启动位置
        ''' </summary>
        ''' <remarks></remarks>
        Protected Overridable Sub DefaultStartPosition()
            Me.MoveToCenterScreen()
        End Sub

        Protected Overrides Sub OnCreateControl()
            Me.m_FormImage = Me.InitFormImage()
            Me.SetBounds(0, 0, Me.m_FormImage.Width, Me.m_FormImage.Height)
            Me.DefaultStartPosition()

            MyBase.OnCreateControl()
        End Sub

        Protected Overrides Sub OnClosing(ByVal e As System.ComponentModel.CancelEventArgs)
            Me.m_haveHandle = False
            Me.Dispose()

            MyBase.OnClosing(e)
        End Sub

        Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
            Me.initializeStyles()
            MyBase.OnHandleCreated(e)
            Me.m_haveHandle = True
        End Sub

        Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
            Get
                Dim _CreateParams As Windows.Forms.CreateParams = MyBase.CreateParams
                _CreateParams.ExStyle = _CreateParams.ExStyle Or &H80000
                Return _CreateParams
            End Get
        End Property

        Protected Overrides Sub OnVisibleChanged(ByVal e As System.EventArgs)
            MyBase.OnVisibleChanged(e)

            Me.UpdateVisual(Me.FormImage)
        End Sub


        '[public]----------------------------------------------------------------------------------------

        ''' <summary>
        ''' 移动到屏幕中心点
        ''' </summary>
        Public Sub MoveToCenterScreen()
            Dim _Point As Point = Me.ScreenCenterPoint()
            Me.Left = CInt(_Point.X - Me.FormImage.Width / 2)
            Me.Top = CInt(_Point.Y - Me.FormImage.Height / 2)
        End Sub

#Region "old"
        '''' <summary>
        '''' 设置图片
        '''' </summary>
        '''' <remarks></remarks>
        'Private Sub setImage()
        '    If Me.m_haveHandle = False Then Exit Sub
        '    If Me.m_FormImage Is Nothing Then Exit Sub

        '    Dim _Bitmap As Bitmap = DirectCast(Me.m_FormImage, Bitmap)

        '    If Drawing.Bitmap.IsCanonicalPixelFormat(_Bitmap.PixelFormat) = False OrElse _
        '       Drawing.Bitmap.IsAlphaPixelFormat(_Bitmap.PixelFormat) = False Then
        '        Throw New ApplicationException("The picture must be 32bit picture with alpha channel.")
        '    End If

        '    Dim _OldBits As IntPtr = IntPtr.Zero
        '    Dim _ScreenDC As IntPtr = User32Dll.GetDC(IntPtr.Zero)
        '    Dim _HBitmat As IntPtr = IntPtr.Zero
        '    Dim _MemDc As IntPtr = GDI32Dll.CreateCompatibleDC(_ScreenDC)

        '    Try
        '        Dim _TopLoc As New ExPOINT(Me.Left, Me.Top)
        '        Dim _BitmapSize As New ajayumi.library.Api.VBasic.SIZE(_Bitmap.Width, _Bitmap.Height)
        '        Dim _BlendFun As New BLENDFUNCTION(AC_SRC_OVER, 0, 255, AC_SRC_ALPHA)
        '        Dim _SrcLoc As New Drawing.Point(0, 0)
        '        _HBitmat = _Bitmap.GetHbitmap(Drawing.Color.FromArgb(0))
        '        _OldBits = GDI32Dll.SelectObject(_MemDc, _HBitmat)

        '        User32Dll.UpdateLayeredWindow(Handle, _ScreenDC, _TopLoc, _BitmapSize, _MemDc, _SrcLoc, 0, _BlendFun, ULW_ALPHA)

        '    Catch ex As Exception
        '        ' TODO: 移除
        '    Finally
        '        If _HBitmat <> IntPtr.Zero Then
        '            GDI32Dll.SelectObject(_MemDc, _OldBits)
        '            GDI32Dll.DeleteObject(_HBitmat)
        '        End If

        '        User32Dll.ReleaseDC(IntPtr.Zero, _ScreenDC)
        '        GDI32Dll.DeleteDC(_MemDc)
        '    End Try
        'End Sub
#End Region


        ''' <summary>
        ''' 更新可视的图像
        ''' </summary>
        ''' <param name="img">待更新的图像</param>
        Public Sub UpdateVisual(ByVal img As Image)
            Me.UpdateVisual(img, Me.Left, Me.Top)
        End Sub

        ''' <summary>
        ''' 更新可视的图像
        ''' </summary>
        ''' <param name="img">待更新的图像</param>
        ''' <param name="left">左边距</param>
        ''' <param name="top">上边距</param>
        Public Sub UpdateVisual(ByVal img As Image, ByVal left As Integer, ByVal top As Integer)
            If Me.m_haveHandle = False Then Exit Sub
            If Me.m_FormImage Is Nothing Then Exit Sub

            Dim _Bitmap As Bitmap = DirectCast(img, Bitmap)

            If Drawing.Bitmap.IsCanonicalPixelFormat(_Bitmap.PixelFormat) = False OrElse _
               Drawing.Bitmap.IsAlphaPixelFormat(_Bitmap.PixelFormat) = False Then
                Throw New ApplicationException("The picture must be 32bit picture with alpha channel.")
            End If

            Dim _OldBits As IntPtr = IntPtr.Zero
            Dim _ScreenDC As IntPtr = User32Dll.GetDC(IntPtr.Zero)
            Dim _HBitmat As IntPtr = IntPtr.Zero
            Dim _MemDc As IntPtr = GDI32Dll.CreateCompatibleDC(_ScreenDC)

            Try
                Dim _TopLoc As New PointEx(left, top)
                Dim _BitmapSize As New SizeEx(_Bitmap.Width, _Bitmap.Height)
                Dim _BlendFun As New BLENDFUNCTION(AC_SRC_OVER, 0, 255, AC_SRC_ALPHA)
                Dim _SrcLoc As New Drawing.Point(0, 0)
                _HBitmat = _Bitmap.GetHbitmap(Drawing.Color.FromArgb(0))
                _OldBits = GDI32Dll.SelectObject(_MemDc, _HBitmat)

                User32Dll.UpdateLayeredWindow(Handle, _ScreenDC, _TopLoc, _BitmapSize, _MemDc, _SrcLoc, 0, _BlendFun, ULW_ALPHA)

            Catch ex As Exception
                ' TODO: 移除
            Finally
                If _HBitmat <> IntPtr.Zero Then
                    GDI32Dll.SelectObject(_MemDc, _OldBits)
                    GDI32Dll.DeleteObject(_HBitmat)
                End If

                User32Dll.ReleaseDC(IntPtr.Zero, _ScreenDC)
                GDI32Dll.DeleteDC(_MemDc)
            End Try
        End Sub

        ''' <summary>
        ''' 更新位置
        ''' </summary>
        ''' <param name="left"></param>
        ''' <param name="top"></param>
        Public Sub UpdateLocation(ByVal left As Integer, ByVal top As Integer)
            Me.Left = left
            Me.Top = top

            Me.UpdateVisual(Me.FormImage)
        End Sub

        ''' <summary>
        ''' 更新窗体图片
        ''' </summary>
        ''' <param name="img"></param>
        Public Sub UpdateFormImage(ByVal img As Image)
            Me.m_FormImage = img
            Me.UpdateVisual(img)
        End Sub


#End Region


    End Class

End Namespace